import java.net.*;
import java.nio.ByteBuffer;
import java.util.*;

class ReceiverThread extends Thread {

	private boolean stopped = false;
	
	Com com;
	
	String myName;
	
	Map<String,Short> currentSeqNo;
	
	public ReceiverThread(Com com_var, String name) throws SocketException {
		this.com = com_var;
		this.myName = name;
		currentSeqNo = new HashMap<String, Short>();
	}
	
	public void halt() {
		this.stopped = true;
	}
	
	public void run() {
		
		while (true) {
			if (stopped) return;
			ByteBuffer receiveBuf = ByteBuffer.allocate(1000) ;
			com.receive(receiveBuf);
			MyMessage msg = new MyMessage(receiveBuf);
			if(! (msg.getSurNom()).equals(myName)){ //do not receive messages created by myself
				switch(msg.getID()) {
					case 0: //INIT
						processInit(msg);
						break;
					case 1: //DATA
						processData(msg);
						break;
					case 2: //REPLY
						processReply(msg);
						break;
					case 3: //REORDER
						processReorder(msg);
						break;
					default:
						msg.printAllField();
						return;
				}	
			}
			
			Thread.yield();
		}
	}
	
	private void processReorder(MyMessage msg) {
		String[] x = (msg.getMessage()).split("\\ ");
		String destName = x[x.length - 1];
//		System.out.println("destName:" + destName);
//		msg.printAllField();
		if(destName.equals(myName)){
			System.out.println("get a Reorder from " + msg.getSurNom() + " seq=" + msg.getSeq());
			String msgContent = "RE_hello_" + msg.getSeq() + " to " + msg.getSurNom() ;
			MyMessage reMsg = new MyMessage(myName, msg.getSeq(), msgContent);
			com.send(reMsg.getBuf());	
		}
	}

	private void processInit(MyMessage msg) {
		msg.printAllField();
		short seq = 9999;
		String msgContent = "I am: " + myName + " reply for seq=" + msg.getSeq() + " of " + msg.getSurNom();
		MyMessage reply = new MyMessage((short)2, myName, seq, msgContent);				
		com.send (reply.getBuf());			
	}

	private void processReply(MyMessage msg) {
		msg.printAllField();	
	}

	void processData(MyMessage msg){
		System.out.println();
		msg.printAllField();
		
		short receivedSeq = msg.getSeq();
		String sender = msg.getSurNom();
		try{
			short currentSeq = currentSeqNo.get(sender);
			
			if(receivedSeq > currentSeq + 1){// loss seq
				System.out.println("--> Loss: " + sender + "'s data packets from " + (currentSeq+1) + " to " + receivedSeq);
				//reorder
				short numReorder = (short)(receivedSeq - (currentSeq+1));
				for(short i=1; i < numReorder; i++){
					MyMessage reorder = new MyMessage((short)3, myName, (short)(currentSeq + i), "reorder " + sender);
					com.send(reorder.getBuf());
				}
			}
			else if(receivedSeq == currentSeq + 1){// correct seq
				currentSeqNo.put(msg.getSurNom(), msg.getSeq()); //update currentSeqNo 			
			}
			else{//doublon
				System.out.println("--> Doublon: DATA seq=" + receivedSeq + " sender=" + sender);
			}
		}
		catch(NullPointerException e){
			System.out.println("--> New sender: " + msg.getSurNom());
			currentSeqNo.put(msg.getSurNom(), msg.getSeq()); //first insert currentSeqNo
		}
		
//		printCurrentSeqNo();
	}
	
	void printCurrentSeqNo(){ //for tracing
		List<String> listSenders = new ArrayList<String>(currentSeqNo.keySet());
		for(String str: listSenders){
			System.out.println(str + " " + currentSeqNo.get(str));
		}
	}
	
}